package com.gitee.wsl.common.ui.ext.color

import androidx.compose.ui.graphics.Color
import kotlin.jvm.JvmInline
import kotlin.math.roundToInt

@OptIn(ExperimentalStdlibApi::class)
val Color.hexString: String
    get() {
        return hex().value
        /*val a = (alpha * 255).toInt()
        val r = (red * 255).toInt()
        val g = (green * 255).toInt()
        val b = (blue * 255).toInt()*/

        //return String.format("%02X%02X%02X%02X", a, r, g, b)
    }

val Color.hexadecimal: String
    get() = ("#" + encodeChannel(this.alpha) + encodeChannel(this.red) + encodeChannel(this.green) + encodeChannel(this.blue))

private fun encodeChannel(number: Float): String {
    require(!(number < 0 || number > 1.0f)) { "" + number }
    val hex = "0123456789ABCDEF"
    val asInt = (255.0f * number + 0.5f).toInt()
    val hexaDigit1 = hex[asInt / 16]
    val hexaDigit2 = hex[asInt % 16]
    return hexaDigit1.toString() + "" + hexaDigit2
}

/**
 * Value wrapper of a hexadecimal representation of a [Color].
 */
@JvmInline
value class Hex(val value: String)

/**
 * The [Color] associated with an ARGB or RGB hexadecimal representation.
 */
fun Hex.color(): Color {
    var hex = value.removePrefix("#")
    if (hex.length == 6) {
        // Alpha not specified so append full opacity.
        hex = "FF${hex}"
    }

    check(hex.length == 8) {
        "Hex value has a length of ${hex.length} but a length of 6 or 8 is required without a # prefix OR a length of 7 or 9 characters with a # prefix."
    }

    return Color(hex.toLong(radix = 16))
}

/**
 * The [Color] associated with an ARGB or RGB hexadecimal representation, or null if the [Hex.value] is unable to be converted.
 */
fun Hex.colorOrNull(): Color? = try {
    color()
} catch (ex: Exception) {
    null
}

/**
 * The hexadecimal representation of this [Color] in ARGB format.
 */
fun Color.hex(): Hex {
    fun Float.convert() = (this * 255).toLong().toString(radix = 16).padStart(length = 2, padChar = '0')
    val alpha = alpha.convert()
    val red = red.convert()
    val green = green.convert()
    val blue = blue.convert()
    return Hex("#$alpha$red$green$blue")
}

/** Converts a [Color] to a RGBA formatted color `#RRGGBBAA` hex string; e.g., `#FFFFFF1A` (a translucent white). */
@OptIn(ExperimentalStdlibApi::class)
fun Color.toRgbaHexString(): String {
    val r = (red * 255).roundToInt().toHexString()
    val g = (green * 255).roundToInt().toHexString()
    val b = (blue * 255).roundToInt().toHexString()

    return buildString {
        append('#')
        append(r.padStart(2, '0'))
        append(g.padStart(2, '0'))
        append(b.padStart(2, '0'))

        if (alpha != 1.0f) {
            val a = (alpha * 255).roundToInt().toHexString()
            append(a.padStart(2, '0'))
        }
    }
}

/** Converts a RGBA formatted color `#RRGGBBAA` hex string to a [Color]; e.g., `#FFFFFF1A` (a translucent white). */
fun Color.Companion.fromRGBAHexStringOrNull(rgba: String): Color? =
    rgba.lowercase()
        .removePrefix("#")
        .let {
            when (it.length) {
                3 -> "ff${it[0]}${it[0]}${it[1]}${it[1]}${it[2]}${it[2]}"
                4 -> "${it[3]}${it[3]}${it[0]}${it[0]}${it[1]}${it[1]}${it[2]}${it[2]}"
                6 -> "ff$it"
                8 -> "${it[6]}${it[7]}${it[0]}${it[1]}${it[2]}${it[3]}${it[4]}${it[5]}"
                else -> null
            }
        }
        ?.toLongOrNull(radix = 16)
        ?.let { Color(it) }
